package cn.xzc.job.util;

import cn.xzc.job.ErrorHandler;
import cn.xzc.job.pojo.DelegatingErrorHandlingRunnable;

/**
 * @author 熊志聪
 * @Classname JobUtils
 * @Description job相关的util【job出现的异常日志处理、】
 * @Date 2024/2/14 17:37
 */
public class JobUtils {
    /**
     * job异常处理策略-只进行log记录[不会阻止后续程序继续运行]
     */
    public static final ErrorHandler LOG_AND_SUPPRESS_ERROR_HANDLER = new LoggingErrorHandler();

    /**
     * job异常处理策略-先进行log记录+并将异常转成runtime异常抛出[会阻止后续程序继续运行]
     */
    public static final ErrorHandler LOG_AND_PROPAGATE_ERROR_HANDLER = new PropagatingErrorHandler();

    /**
     * 给job添加异常处理策略
     *
     * @param job             要执行的任务
     * @param errorHandler    异常处理策略
     * @param isRepeatingTask 任务是否是重复任务
     * @return (job + 异常处理策略)
     */
    public static DelegatingErrorHandlingRunnable decorateTaskWithErrorHandler(
            Runnable job, ErrorHandler errorHandler, boolean isRepeatingTask) {

        if (job instanceof DelegatingErrorHandlingRunnable) {
            return (DelegatingErrorHandlingRunnable) job;
        }
        //获取异常处理策略
        ErrorHandler eh = (errorHandler != null ? errorHandler : getDefaultErrorHandler(isRepeatingTask));
        return new DelegatingErrorHandlingRunnable(job, eh);
    }

    /**
     * 获取默认的job异常处理策略
     * 1. 要执行的runnable是重复的，则直接记录异常抛出信息
     * 2. 要执行的runnable是一次性的，则将异常抛出信息记录到日志，并将异常抛出为runtime异常
     *
     * @param isRepeatingTask 是否是重复任务
     * @return 默认的job异常处理策略
     */
    public static ErrorHandler getDefaultErrorHandler(boolean isRepeatingTask) {
        return (isRepeatingTask ? LOG_AND_SUPPRESS_ERROR_HANDLER : LOG_AND_PROPAGATE_ERROR_HANDLER);
    }

    /**
     * job异常处理策略-只进行log记录
     */
    private static class LoggingErrorHandler implements ErrorHandler {
        private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LoggingErrorHandler.class);

        @Override
        public void handleError(Throwable t) {
            log.error("Unexpected error occurred in scheduled job", t);
        }
    }

    /**
     * job异常处理策略-先进行log记录+并将异常转成runtime异常抛出
     */
    private static class PropagatingErrorHandler extends LoggingErrorHandler {
        @Override
        public void handleError(Throwable t) {
            super.handleError(t);
            ReflectUtil.rethrowRuntimeException(t);
        }
    }
}
